home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 176-200 / scopedisk185 / dfc5 / disktask.c < prev    next >
C/C++ Source or Header  |  1995-03-19  |  9KB  |  345 lines

  1. #include "DFC5.h"
  2.  
  3. extern struct MsgPort *TaskPort[6], *MainPort, *TPort;
  4. extern struct IMsg IMsg[6];
  5.  
  6. static char *TaskBuffer[5];            /* local buffers (for doing I/O) */
  7. static char *Buffer[80];                /* pointers to the 80 buffer chunks */
  8. static long CheckSum[80];                /* checksums of the internal RAM buffer */
  9. struct IOStdReq *IOStdReq[4];            /* our I/O request blocks */
  10.  
  11.  
  12.  
  13. /*
  14.  *      This routine attempts to allocate 80 buffers. Return 0 on failure, otherwise
  15.  *   the denominator of the fraction of a disk allocated (1=entire disk, 2=half
  16.  *   disk, etc. upto 4). Note than when 3 is returned, actually 80/3+1 tracks
  17.  *   were allocated.
  18.  */
  19. int AllocBuffers(void) {
  20.  
  21.     register int i;
  22.  
  23.     for (i=0; i<80; i++)
  24.         if ((Buffer[i]=AllocMem((long)TRACKSIZE, MEMF_PUBLIC))==NULL) {
  25.             if (i>=40) {
  26.                 FreeBuffers(40);
  27.                 return(2);
  28.             }
  29.             else if (i>=27) {
  30.                 FreeBuffers(27);
  31.                 return(3);
  32.             }
  33.             else if (i>=20) {
  34.                 FreeBuffers(20);
  35.                 return(4);
  36.             }
  37.             else {
  38.                 FreeBuffers(0);
  39.                 return(0);
  40.             }
  41.         }
  42.     return(1);
  43. }
  44.  
  45. /*
  46.  *      And this routine lets them go from a defined index.
  47.  */
  48. void FreeBuffers(int i) {
  49.  
  50.     while(i<80) {
  51.         if (Buffer[i]) {
  52.             FreeMem(Buffer[i], TRACKSIZE);
  53.             Buffer[i] = NULL;
  54.         }
  55.         i++;
  56.     }
  57. }
  58.  
  59. /*
  60.  *      We attempt to create an I/O request.     We allocate memory for it and
  61.  *      for its port.
  62.  */
  63. struct IOStdReq *CreateIOStdReq(void) {
  64.  
  65.     register struct IOStdReq *IOStdReq;
  66.  
  67.     if (!(IOStdReq = AllocMem(sizeof(struct IOStdReq), MEMF_CLEAR | MEMF_PUBLIC))) return (NULL);
  68.     IOStdReq->io_Message.mn_Node.ln_Type = NT_MESSAGE;
  69.     IOStdReq->io_Message.mn_Length = sizeof(struct IOStdReq)-sizeof(struct Message);
  70.     if ((IOStdReq->io_Message.mn_ReplyPort = CreatePort(NULL,0))==NULL) {
  71.         FreeMem(IOStdReq, sizeof(struct IOStdReq));
  72.         return(NULL);
  73.     }
  74.     return(IOStdReq);
  75. }
  76.  
  77. /*
  78.  *      This routine frees an I/O request.
  79.  */
  80. void DeleteIOStdReq(struct IOStdReq *IOStdReq) {
  81.  
  82.     DeletePort(IOStdReq->io_Message.mn_ReplyPort);
  83.     FreeMem(IOStdReq, sizeof(struct IOStdReq));
  84. }
  85.  
  86. /*
  87.  *      This routine recalculates the checksum for a block, and updates it in
  88.  *      word 5.  The sum of all the words in a block must be 0.
  89.  */
  90. void ReCheck(long *w) {
  91.  
  92.     register int i;
  93.     register long CheckSum;
  94.  
  95.     CheckSum = 0;
  96.     for (i=0; i<128; i++)
  97.         CheckSum += w[i];
  98.     w[5] -= CheckSum;
  99. }
  100.  
  101. /*
  102.  *      This routine checksums a track of the internal RAM buffer.
  103.  */
  104.  
  105. long Check(long *Track) {
  106.  
  107.     register int i;
  108.     register long CheckSum = 0;
  109.  
  110.     for (i=0; i<(TRACKSIZE/sizeof(long)); i++) CheckSum += Track[i];
  111.     return(CheckSum);
  112. }
  113.  
  114.  
  115. /*
  116.  *      We simply DateStamp the creation date, modification date, and
  117.  *      rechecksum the block. A random factor is added because of multiple
  118.  *      async accesses.
  119.  */
  120. void UpdateRootBlock(char *b) {
  121.  
  122.     static unsigned char Rand;
  123.  
  124.     Rand += 7;
  125.     DateStamp((void *)(b + 420));
  126.     DateStamp((void *)(b + 484));
  127.     ((struct DateStamp *)(b + 420))->ds_Tick = (((struct DateStamp *)(b + 420))->ds_Tick+Rand)%3000;
  128.     ((struct DateStamp *)(b + 484))->ds_Tick = (((struct DateStamp *)(b + 484))->ds_Tick+Rand)%3000;
  129.     ReCheck((void *)b);
  130. }
  131.  
  132. /*
  133.  *      This routine creates data for the format option.     Note the clever
  134.  *      way the data is built up; this routine should build a disk exactly
  135.  *      the same way the standard AmigaDOS format does.    If we are on track
  136.  *      40, some additional work must be done to create a root block and
  137.  *      bitmap, but it's not too bad. I don't know if this is the right
  138.  *   way to do under FFS, but since it works . . .
  139.  */
  140. void MakeFormatData(int Track, char *b, int UseFFS) {
  141.  
  142.     register long *p;
  143.     register long cs;
  144.     register long i;
  145.     register unsigned char *q;
  146.  
  147.     p = (long *)b;
  148.     cs = (((ULONG)('D') << 24) | ((ULONG)('O') << 16) | ((ULONG)('S') << 8) | (UseFFS ? '\1' : '\0')) + (((long)Track & 48) << 16);
  149.     for (i=0; i<TRACKSIZE/4; i++)
  150.         *p++ = cs + (i & 3327);
  151.     if (Track != 40)
  152.         return;
  153.     p = (long *)b;
  154.     for (i=0; i<256; i++)
  155.         *p++ = 0;
  156.     p = (long *)b;
  157.     p[0] = 2;
  158.     p[3] = 0x48;
  159.     p[78] = 1;
  160.     p[79] = 0x371;
  161.     q = (unsigned char *)(p + 108);
  162.     strcpy(q+1, "Empty");
  163.     *q = strlen(q+1);
  164.     p[127] = 1;
  165.     p += 128;
  166.     for (i=1; i<55; i++)
  167.         p[i] = 0xffffffff;
  168.     p[0] = 0xc000c037;
  169.     p[28] = 0xffff3fff;
  170.     p[55] = 0x3fffffff;
  171. }
  172.  
  173. /*
  174.  * This routine moves the data to write in the suitable buffer. Track is
  175.  * useful only in Unit==4---in this case we write directly in the RAM buffer.
  176.  */
  177.  
  178. void CopyBuffer(void *p, int Unit, int Track) {
  179.     if (Unit<4) fcpy(p, TaskBuffer[Unit]);
  180.     else if (Track>=0) {
  181.         fcpy(p, Buffer[Track]);
  182.         CheckSum[Track] = Check((long *)Buffer[Track]);
  183.     }
  184. }
  185.  
  186.  
  187.  
  188. /*
  189.  *      Now we try to allocate a disk.     First, we attempt to allocate an
  190.  *      I/O request, and then we actually open the device.    If either of
  191.  *      these fail, we return 0.     This can occur if a drive is opened that
  192.  *      doesn't exist.
  193.  */
  194. int OpenDisk(int Unit) {
  195.  
  196.     register struct IOStdReq **p = &IOStdReq[Unit];
  197.  
  198.     if (*p) return(1);
  199.  
  200.     if ((*p = CreateIOStdReq()) && OpenDevice(TD_NAME, Unit, (void *)*p, 0) == 0) return(1);
  201.     else {
  202.         if (*p) {
  203.             DeleteIOStdReq(*p);
  204.             *p = NULL;
  205.         }
  206.         return(0);
  207.     }
  208. }
  209.  
  210. /*
  211.  *      Here we release a disk.    We check that we have it first!    Then, we
  212.  *      close the device, kill the I/O request, and exit.
  213.  */
  214. void CloseDisk(int Unit) {
  215.  
  216.     register struct IOStdReq **p = &IOStdReq[Unit];
  217.  
  218.     if (*p) {
  219.         CloseDevice((void *)*p);
  220.         DeleteIOStdReq(*p);
  221.         *p = NULL;
  222.     }
  223. }
  224.  
  225. /*
  226.  * Here we do our main track I/O with IOStdReq. The routine returns a parsed error field.
  227.  * Notice that the I/O is sync (much simpler), but the overall design of the program
  228.  * makes it automagically async-like.
  229.  */
  230.  
  231. int DoTDIO(int Unit, int Track, void *Buffer, int Command, int Size) {
  232.     if (Unit>3) return(0);
  233.     IOStdReq[Unit]->io_Length = Size;
  234.     IOStdReq[Unit]->io_Data = Buffer;
  235.     IOStdReq[Unit]->io_Command = Command;
  236.     IOStdReq[Unit]->io_Offset = Track * (long)TRACKSIZE;
  237.     DoIO((void *)IOStdReq[Unit]);
  238.     if (IOStdReq[Unit]->io_Error == TDERR_DiskChanged) return(NO_DISK);
  239.     else if (IOStdReq[Unit]->io_Error == TDERR_WriteProt) return(WRITE_PROTECTED);
  240.     else if (IOStdReq[Unit]->io_Error) return(GENERIC_ERROR);
  241.     else return(0);
  242. }
  243.  
  244.  
  245. /*
  246.  * This code is executed by (max) *FIVE* tasks at the same time. It manages a disk
  247.  * (which is deduced from the UserData of the task structure) using a message passing
  248.  * interface. If the unit number is 4, it manages the internal 80 tracks buffer.
  249.  * This code is executed at priority 1.
  250.  */
  251.  
  252. __saveds void DiskTask(void) {
  253.  
  254.     void *VerifyBuffer;
  255.     int AllocFlag, Passes;
  256.  
  257.     register struct IMsg *Message;
  258.     register int Unit = (int)FindTask(NULL)->tc_UserData;
  259.     register int n;
  260.  
  261.     AllocFlag = ((TaskPort[Unit] = CreatePort(NULL, 0)) != NULL);
  262.  
  263.     if (Unit<4) {
  264.         AllocFlag &= OpenDisk(Unit);
  265.         AllocFlag &= ((VerifyBuffer = AllocMem(TRACKSIZE, MEMF_CHIP))!=NULL);
  266.         AllocFlag &= ((TaskBuffer[Unit] = AllocMem(TRACKSIZE, MEMF_CHIP))!=NULL);
  267.     }
  268.     else AllocFlag &= ((Passes = IMsg[Unit].im_n = AllocBuffers()) != 0);
  269.  
  270.     IMsg[Unit].im_RC = AllocFlag;
  271.  
  272.     if (!AllocFlag) goto GameOver;
  273.  
  274.     PutMsg(TPort, (struct Message *)&IMsg[Unit]);
  275.     SetTaskPri(FindTask(NULL), 1);
  276.  
  277.     FOREVER {
  278.         WaitPort(TaskPort[Unit]);
  279.  
  280.         while(Message = (void *)GetMsg(TaskPort[Unit])) {
  281.  
  282.             Message->im_RC = 0;
  283.             n = Message->im_n;
  284.             if (Unit == 4) n = n % (80/Passes+(Passes==3));
  285.  
  286.             switch(Message->im_Action) {
  287.  
  288.                 case INIT:    if (n<0 && Unit<4) {
  289.                                     if (!DoTDIO(Unit, 0, VerifyBuffer, CMD_READ, 512) && (*((unsigned long *)VerifyBuffer) != (((ULONG)('D') << 24) | ((ULONG)('O') << 16) | ((ULONG)('S') << 8) | '\0') && *((unsigned long *)VerifyBuffer) != (((ULONG)('D') << 24) | ((ULONG)('O') << 16) | ((ULONG)('S') << 8) | '\1')))
  290.                                         Message->im_RC = NOT_DOS;
  291.                                     n = 79;
  292.                                 }
  293.                                 DoTDIO(Unit, n, 0, TD_SEEK, TRACKSIZE);
  294.                                 break;
  295.  
  296.                 case STOP_MOTOR:    DoTDIO(Unit, 0, 0, TD_MOTOR, 0);
  297.                                         break;
  298.  
  299.                 case READ_TRACK : if (Unit<4) {
  300.                                             if ((Message->im_RC = DoTDIO(Unit, n, TaskBuffer[Unit], CMD_READ, TRACKSIZE)) == GENERIC_ERROR)
  301.                                                 Message->im_RC = READ_ERROR;
  302.                                             Message->im_p = TaskBuffer[Unit];
  303.                                         }
  304.                                         else {
  305.                                             if (CheckSum[n] != Check((long *)Buffer[n])) Message->im_RC = READ_ERROR;
  306.                                             Message->im_p = Buffer[n];
  307.                                         }
  308.                                         break;
  309.  
  310.                 case WRITE_TRACK :
  311.                 case WRITE_AND_VERIFY_TRACK:
  312.                                         if (Unit<4) {
  313.                                             if ((Message->im_RC = DoTDIO(Unit, n, TaskBuffer[Unit], TD_FORMAT, TRACKSIZE)) == GENERIC_ERROR)
  314.                                                 Message->im_RC = WRITE_ERROR;
  315.                                             if (Message->im_Action == WRITE_TRACK || Message->im_RC) break;
  316.                                             DoTDIO(Unit, n, VerifyBuffer, CMD_READ, TRACKSIZE);
  317.                                             Message->im_RC = (fcmp(TaskBuffer[Unit], VerifyBuffer) ? VERIFY_ERROR : 0);
  318.                                         }
  319.                                         break;
  320.  
  321.                 case EXIT:    goto GameOver;
  322.             }
  323.  
  324.             ReplyMsg((void *)Message);
  325.         }
  326.     }
  327.  
  328. GameOver:
  329.     SetTaskPri(FindTask(NULL), 127);
  330.     if (TaskPort[Unit]) {
  331.         DeletePort(TaskPort[Unit]);
  332.         TaskPort[Unit] = NULL;
  333.     }
  334.  
  335.     if (Unit<4) {
  336.         if (VerifyBuffer) FreeMem(VerifyBuffer, TRACKSIZE);
  337.         if (TaskBuffer[Unit]) FreeMem(TaskBuffer[Unit], TRACKSIZE);
  338.         TaskBuffer[Unit] = NULL;
  339.         CloseDisk(Unit);
  340.     }
  341.     else FreeBuffers(0);
  342.     PutMsg(TPort, (struct Message *)&IMsg[Unit]);
  343.     return;
  344. }
  345.